package org.grottarossa.ui.core.components.tables;



import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Hashtable;

import org.grottarossa.ui.DateHelper;
import org.grottarossa.ui.core.ApplicationSession;
import org.grottarossa.ui.core.StylesConstants;
import org.grottarossa.ui.core.components.TMSNativeSelect;
import org.grottarossa.ui.core.container.TableContainer;
import org.vaadin.henrik.superimmediatetextfield.SuperImmediateTextField;

import com.vaadin.data.Container;
import com.vaadin.data.Item;
import com.vaadin.data.Property;
import com.vaadin.data.Property.ValueChangeEvent;
import com.vaadin.data.Property.ValueChangeListener;
import com.vaadin.data.validator.DoubleValidator;
import com.vaadin.data.validator.IntegerValidator;
import com.vaadin.terminal.Sizeable;
import com.vaadin.ui.CheckBox;
import com.vaadin.ui.Component;
import com.vaadin.ui.DateField;
import com.vaadin.ui.DefaultFieldFactory;
import com.vaadin.ui.Field;
import com.vaadin.ui.Form;
import com.vaadin.ui.TableFieldFactory;
import com.vaadin.ui.TextField;

/***
 * Factory per i controlli da aggiungere alla riga dei filtri nelle tabelle con filtraggi
 * @author 
 *
 */
public class TMSTableFilterFieldFactory extends DefaultFieldFactory
implements ValueChangeListener
{
	/*** Tabella correlata ***/
	private final TMSFilteredTable m_table;

	/*** Mappa campo/property ***/
	private Hashtable<Field, String> m_mapFieldToProperty = new Hashtable<Field, String>();

	/*** Mappa property/campo ***/
	private Hashtable<String, Field> m_mapPropertyToField = new Hashtable<String, Field>();

	/*** Questa variabile serve per evitare chiamate ricorsive durante l'applicazione del filtro al container ***/
	private boolean m_enableFiltering = true;

	/*** Lista dei campi filtro che devono essere trattati come combo ***/
	private ArrayList<String> m_comboFields;

	private final ApplicationSession m_appSession;

	public TMSTableFilterFieldFactory(ApplicationSession appSession, TMSFilteredTable table)
	{
		this.m_appSession = appSession;
		this.m_table = table;
		m_comboFields = new ArrayList<String>();
	}

	@Override
	public Field createField(Container container, Object itemId, Object propertyId, Component uiContext)
	{
		if(m_mapPropertyToField.containsKey(propertyId.toString()))
			return m_mapPropertyToField.get(propertyId.toString());

		Property containerProperty = container.getContainerProperty(itemId, propertyId);
        Class<?> type = containerProperty.getType();

        Field field = null;

        if(m_comboFields.contains(propertyId))
        {
        	field = new TMSNativeSelect(m_appSession.getDataSourceProvider(), null);
        	FilteredContainerWrapper c = (FilteredContainerWrapper)m_table.getContainerDataSource();
        	ArrayList<Object> values = c.getPropertyValues(propertyId);

        	if(!values.contains(""))
        		((TMSNativeSelect)field).addItem("");	//Elemento vuoto

        	for(Object value : values)
        	{
        		((TMSNativeSelect)field).addItem(value);
        	}
        }
        else
        	field = createFieldByType(type);

        if(field != null)
        {
        	m_mapFieldToProperty.put(field, propertyId.toString());
            m_mapPropertyToField.put(propertyId.toString(), field);
            field.setWidth(100, Sizeable.UNITS_PERCENTAGE);
            field.addListener(this);
        }

        return field;
	}

	/***
	 * Crea il giusto campo filtro in base alla tipologia
	 * @param type
	 * @return
	 */
	private Field createFieldByType(Class<?> type)
	{
		Field f = null;

        // Null typed properties can not be edited
        if (type == null)
            return null;

        // Date field
        if (Calendar.class.isAssignableFrom(type))
        {
            f = new DateField();
            ((DateField)f).setResolution(DateField.RESOLUTION_DAY);
            ((DateField)f).setImmediate(true);
            f.addStyleName(StylesConstants.TABLE_FILTER_DATE);
        }

        // Text field
        if (String.class.isAssignableFrom(type) || BigDecimal.class.isAssignableFrom(type)
    		|| Integer.class.isAssignableFrom(type))
        {
            f = new SuperImmediateTextField();

            ((SuperImmediateTextField)f).setNullRepresentation("");
            ((SuperImmediateTextField)f).setImmediate(true);
            ((SuperImmediateTextField)f).setWriteThrough(true);

            if(BigDecimal.class.isAssignableFrom(type))
            	f.addValidator(new DoubleValidator("Formato non valido"));
            else if(Integer.class.isAssignableFrom(type))
            	f.addValidator(new IntegerValidator("Formato non valido"));

            f.addStyleName("tablefilter");
        }

        return f;
    }

	/***
	 * Gestisce l'evento di cambiamento valore di un campo filtro
	 */
	public void valueChange(ValueChangeEvent event)
	{
		if(m_enableFiltering)
		{
			m_enableFiltering = false;

			Property p = event.getProperty();

			FilteredContainerWrapper tc = (FilteredContainerWrapper)m_table.getContainerDataSource();

			Object filterValue = p.getValue();

			if(filterValue instanceof String)
			{
				if(filterValue == null)
					filterValue = "";
			}
			else if(filterValue instanceof Date)
				filterValue = DateHelper.DateToGregorianCalendar(((Date)p.getValue()));

			if(filterValue != null)
				tc.setFilter(m_mapFieldToProperty.get(p), filterValue);
			else
				tc.removeFilter(m_mapFieldToProperty.get(p));

			((Field)p).focus();

			if(filterValue instanceof String && filterValue != null && p instanceof SuperImmediateTextField)
			{
				int cursorPosition = ((String)filterValue).length();
				((SuperImmediateTextField)p).setCursorPosition(cursorPosition);
			}
		}

		m_enableFiltering = true;
	}

	/***
	 * Imposta il tipo di campo filtro di una colonna come combo
	 * @param property Nome della property
	 */
	public void setFieldFilterTypeAsCombo(String property)
	{
		m_comboFields.add(property);
	}

}
